-- Analisador sintático e funções relacionadas.

module Sintatico
( 
	sintatico
) where

import Debug.Trace
import Tokens
import Data.Char
import Types


-- Gera uma string com uma mensagem de erro formatada
-- Linha, Causa/Descrição do erro
makeError :: Int -> String -> String
makeError line msg = "Um erro foi encontrado na linha número: " ++ (show line) ++ "\n[> " ++ msg ++ " <]"

-- Analisador Sintático
-- Recebe a saída do analisador léxico e valida
sintatico :: [TLine] -> (Bool, Error)
sintatico tks =
	case tks of
		[] -> (True, "")
		(l1, Program_tk):(l2, (Identifier_tk a)):b ->
			let (f, error) = valVar b in
			if f then
				(True, error)
			else
				(False, error)
			
			

-- Analisa declaração de variáveis
valVar :: [TLine] -> (Bool, Error)
valVar tks =
	case tks of
		[] -> (True, "")
		(l1, Define_tk):a -> valVar a
		(l1, (Integer_tk a)):(l2, (Identifier_tk b)):(l3, PontoVirgula_tk):c -> valVar c
		(l1, (Integer_tk a)):(l2, (Identifier_tk b)):(l3, Equals_tk):(l4, (Integer_tk c)):(l5, PontoVirgula_tk):d -> valVar d
		(l1, (Integer_tk a)):(l2, (Identifier_tk b)):(l3, ParentesesL_tk):(lx, Integer_tk c):(l4, ParentesesR_tk):(l5, PontoVirgula_tk):d -> valVar d
		(l1, (Integer_tk a)):(l2, (Identifier_tk b)):(l3, Virgula_tk):c -> 
			let (f, s) = valVarAux c in
			if f then
				valVar s
			else
				(False, makeError l1 "Erro de sintaxe: Declaração de variável")
		(l1, (Integer_tk a)):(l2, (Identifier_tk b)):(l3, ParentesesL_tk):(lx, Integer_tk c):(l4, ParentesesR_tk):(l5, Virgula_tk):d ->
			let (f, s) = valVarAux d in
			if f then
				valVar s
			else
				(False, makeError l1 "Erro de sintaxe: Declaração de variável")
		
		(l1, (Character_tk a)):(l2, (Identifier_tk b)):(l3, PontoVirgula_tk):c -> valVar c
		(l1, (Character_tk a)):(l2, (Identifier_tk b)):(l3, Equals_tk):(l4, (Character_tk c)):(l5, PontoVirgula_tk):d -> valVar d
		(l1, (Character_tk a)):(l2, (Identifier_tk b)):(l3, ParentesesL_tk):(lx, Integer_tk c):(l4, ParentesesR_tk):(l5, PontoVirgula_tk):d -> valVar d
		(l1, (Character_tk a)):(l2, (Identifier_tk b)):(l3, Virgula_tk):c ->
			let (f, s) = valVarAux c in
			if f then
				valVar s
			else
				(False, makeError l1 "Erro de sintaxe: Declaração de variável")
		(l1, (Character_tk a)):(l2, (Identifier_tk b)):(l3, ParentesesL_tk):(lx, Integer_tk c):(l4, ParentesesR_tk):(l5, Virgula_tk):d ->
			let (f, s) = valVarAux d in
			if f then
				valVar s
			else
				(False, makeError l1 "Erro de sintaxe: Declaração de variável")
		
		(l1, (Logical_tk a)):(l2, (Identifier_tk b)):(l3, PontoVirgula_tk):c -> valVar c
		(l1, (Logical_tk a)):(l2, (Identifier_tk b)):(l3, Equals_tk):(l4, (Logical_tk c)):(l5, PontoVirgula_tk):d -> valVar d
		(l1, (Logical_tk a)):(l2, (Identifier_tk b)):(l3, ParentesesL_tk):(lx, Integer_tk c):(l4, ParentesesR_tk):(l5, PontoVirgula_tk):d -> valVar d
		(l1, (Logical_tk a)):(l2, (Identifier_tk b)):(l3, Virgula_tk):c ->
			let (f, s) = valVarAux c in
			if f then
				valVar s
			else
				(False, makeError l1 "Erro de sintaxe: Declaração de variável")
		(l1, (Logical_tk a)):(l2, (Identifier_tk b)):(l3, ParentesesL_tk):(lx, Integer_tk c):(l4, ParentesesR_tk):(l5, Virgula_tk):d ->
			let (f, s) = valVarAux d in
			if f then
				valVar s
			else
				(False, makeError l1 "Erro de sintaxe: Declaração de variável")
		
		(l1, (Real_tk a)):(l2, (Identifier_tk b)):(l3, PontoVirgula_tk):c -> valVar c
		(l1, (Real_tk a)):(l2, (Identifier_tk b)):(l3, Equals_tk):(l4, (Real_tk c)):(l5, PontoVirgula_tk):d -> valVar d
		(l1, (Real_tk a)):(l2, (Identifier_tk b)):(l3, ParentesesL_tk):(lx, Integer_tk c):(l4, ParentesesR_tk):(l5, PontoVirgula_tk):d -> valVar d
		(l1, (Real_tk a)):(l2, (Identifier_tk b)):(l3, Virgula_tk):c ->
			let (f, s) = valVarAux c in
			if f then
				valVar s
			else
				(False, makeError l1 "Erro de sintaxe: Declaração de variável")
		(l1, (Real_tk a)):(l2, (Identifier_tk b)):(l3, ParentesesL_tk):(lx, Integer_tk c):(l4, ParentesesR_tk):(l5, Virgula_tk):d ->
			let (f, s) = valVarAux d in
			if f then
				valVar s
			else
				(False, makeError l1 "Erro de sintaxe: Declaração de variável")
				
		(l1, (Identifier_tk a)):(l2, (Identifier_tk b)):(l3, PontoVirgula_tk):c -> valVar c
		(l1, (Identifier_tk a)):(l2, (Identifier_tk b)):(l3, Equals_tk):(l4, Identifier_tk c):(l5, PontoVirgula_tk):d -> valVar d
		(l1, (Identifier_tk a)):(l2, (Identifier_tk b)):(l3, ParentesesL_tk):(lx, Integer_tk c):(l4, ParentesesR_tk):(l5, PontoVirgula_tk):d -> valVar d
		(l1, (Identifier_tk a)):(l2, (Identifier_tk b)):(l3, Virgula_tk):c ->
			let (f, s) = valVarAux c in
			if f then
				valVar s
			else
				(False, makeError l1 "Erro de sintaxe: Declaração de variável")
		(l1, (Identifier_tk a)):(l2, (Identifier_tk b)):(l3, ParentesesL_tk):(lx, Integer_tk c):(l4, ParentesesR_tk):(l5, Virgula_tk):d ->
			let (f, s) = valVarAux d in
			if f then
				valVar s
			else
				(False, makeError l1 "Erro de sintaxe: Declaração de variável")
		(l1, a):_ -> (False, makeError l1 "Erro de sintaxe: Declaração de variável")
		
valVarAux :: [TLine] -> (Bool, [TLine])
valVarAux tks =
	case tks of
		[] -> (True, [])
		(l1, (Identifier_tk a)):(l2, Virgula_tk):b -> valVarAux b
		(l1, (Identifier_tk a)):(l2, PontoVirgula_tk):b -> (True, b)
		(l1, (Identifier_tk a)):(l2, ParentesesL_tk):(l3, (Integer_tk b)):(l4, ParentesesR_tk):(l5, Virgula_tk):c -> valVarAux c
		(l1, (Identifier_tk a)):(l2, ParentesesL_tk):(l3, (Integer_tk b)):(l4, ParentesesR_tk):(l5, PontoVirgula_tk):c -> (True, c)
		_ -> (False, [])
